package top.zhangjianyong.blog.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.zhangjianyong.blog.enums.RespCode;
import top.zhangjianyong.blog.constant.ThreadPoolConstant;
import top.zhangjianyong.blog.entity.dto.BlogCategoryDTO;
import top.zhangjianyong.blog.entity.dto.CategoryDTO;
import top.zhangjianyong.blog.entity.po.Category;
import top.zhangjianyong.blog.exception.ApiException;
import top.zhangjianyong.blog.mapper.CategoryMapper;
import top.zhangjianyong.blog.params.category.CategoryRemoveParam;
import top.zhangjianyong.blog.params.category.CategorySaveOrUpdateParam;
import top.zhangjianyong.blog.params.category.CategoryTreeParam;
import top.zhangjianyong.blog.response.ApiResponse;
import top.zhangjianyong.blog.service.BlogService;
import top.zhangjianyong.blog.service.CategoryService;
import top.zhangjianyong.blog.utils.ColorUtil;
import top.zhangjianyong.blog.utils.EntityUtil;

/**
 * 分类
 *
 * @author zhangjianyong
 * @since 2024/7/31 上午10:29
 */
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category>
    implements CategoryService {
  private final BlogService blogService;

  public CategoryServiceImpl(@Lazy BlogService blogService) {
    this.blogService = blogService;
  }

  @Override
  public ApiResponse tree(CategoryTreeParam param) {
    List<CategoryDTO> categoryDTOS = listDTO(param);
    List<CategoryDTO> tree = EntityUtil.toTree(categoryDTOS);

    // 先保存每个分类的直接博客数量到currentCount
    saveCurrentCount(tree);

    // 递归计算包含子分类的博客总数
    calculateTotalCount(tree);

    return ApiResponse.success(tree);
  }

  @Override
  public ApiResponse list(CategoryTreeParam param) {
    List<CategoryDTO> categoryDTOS = listDTO(param);
    // 返回平铺列表，不构建树形结构，不递归计算总数
    return ApiResponse.success(categoryDTOS);
  }

  private List<CategoryDTO> listDTO(CategoryTreeParam unusedParam /* 未使用参数，保留接口一致性 */) {
    List<Category> categories = lambdaQuery().list();
    List<CategoryDTO> categoryDTOS = EntityUtil.entity2DTO(categories, CategoryDTO.class);

    // 统计每个分类直接的博客数量（不包括子分类）
    for (CategoryDTO categoryDTO : categoryDTOS) {
      Long count = blogService.countByCategory(categoryDTO.getId());
      categoryDTO.setCount(count);
      // 同时设置currentCount，在tree接口中会被重新设置
      categoryDTO.setCurrentCount(count);
    }
    return categoryDTOS;
  }

  /**
   * 递归保存每个分类的直接博客数量到currentCount字段
   *
   * @param categories 分类列表
   */
  private void saveCurrentCount(List<CategoryDTO> categories) {
    for (CategoryDTO category : categories) {
      // 保存当前分类的直接博客数量
      category.setCurrentCount(category.getCount());

      if (category.getChildren() != null && !category.getChildren().isEmpty()) {
        // 递归处理子分类
        saveCurrentCount(category.getChildren());
      }
    }
  }

  /**
   * 递归计算分类及其子分类的博客总数
   *
   * @param categories 分类列表
   */
  private void calculateTotalCount(List<CategoryDTO> categories) {
    for (CategoryDTO category : categories) {
      if (category.getChildren() != null && !category.getChildren().isEmpty()) {
        // 先递归计算子分类
        calculateTotalCount(category.getChildren());

        // 计算当前分类的总数：自己的数量 + 所有子分类的数量
        long totalCount = category.getCurrentCount(); // 使用currentCount而不是count
        for (CategoryDTO child : category.getChildren()) {
          totalCount += child.getCount();
        }
        category.setCount(totalCount);
      }
    }
  }

  @Override
  public ApiResponse saveOrUpdate(CategorySaveOrUpdateParam param) {
    Category category = new Category();
    BeanUtils.copyProperties(param, category);

    // 处理颜色值：格式化为标准格式或生成随机颜色
    category.setColor(ColorUtil.safeGetColor(category.getColor()));

    boolean result = null == category.getId() ? save(category) : updateById(category);
    return result
        ? ApiResponse.success(category)
        : ApiResponse.fail(RespCode.CATEGORY_SAVE_OR_UPDATE_ERROR);
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public ApiResponse remove(CategoryRemoveParam param) {

    if (!clearCategoryPid(param.id())) {
      return ApiResponse.fail(RespCode.CATEGORY_CLEAR_REMOVE_ERROR);
    }

    if (!removeById(param.id())) throw new ApiException(RespCode.CATEGORY_REMOVE_ERROR);
    blogService.clearCategory(param.id());
    return ApiResponse.success();
  }

  @Override
  public BlogCategoryDTO getPath(Long id) {
    List<Category> categories = getPath(id, new ArrayList<>());
    Collections.reverse(categories);
    BlogCategoryDTO blogCategoryDTO = new BlogCategoryDTO();
    blogCategoryDTO.setCategoryId(id);
    blogCategoryDTO.setCategories(categories);
    return blogCategoryDTO;
  }

  @Async(ThreadPoolConstant.ASYNC_SQL_EXECUTOR_BEAN)
  @Override
  public CompletableFuture<BlogCategoryDTO> getPathAsync(Long id) {
    return CompletableFuture.completedFuture(getPath(id));
  }

  private List<Category> getPath(Long id, List<Category> list) {
    if (null == id || 0L == id) return list;
    Category category = getById(id);
    list.add(category);
    return getPath(category.getPid(), list);
  }

  /**
   * 删除分类的时候调用，将删除分类的子分类挂到父分类上
   *
   * @param pid 删除分类的id
   * @return 返回处理结果
   */
  private boolean clearCategoryPid(Long pid) {
    Category category = getById(pid);
    return lambdaUpdate()
        .eq(Category::getPid, pid)
        .set(Category::getPid, category.getPid())
        .update();
  }
}
